package process2

import (
	"chatroom/common/message"
	"chatroom/server/model"
	"chatroom/server/utils"
	"encoding/json"
	"fmt"
	"net"
)

type UserProcess struct {
	// 连接
	Conn net.Conn
	// 该 Conn 是哪个用户
	UserId int
}

// 通知所有在线的用户的方法
// userId：通知其它的在线用户，我上线
func (this *UserProcess) NotifyOthersOnlineUser(userId int) {
	// 遍历 onlineUsers , 然后一个一个的发送 NotifyUserStatusMes
	for id, up := range userMgr.onlineUsers {
		// 过滤掉自己
		if id == userId {
			continue
		}
		// 开始通知
		up.NotifyMeOnline(userId)
	}
}

// 通知用户上线消息
func (this *UserProcess) NotifyMeOnline(userId int) {
	// 组装 NotifyUserStatusMes
	var mes message.Message
	mes.Type = message.NotifyUserStatusMesType
	var notifyUserStatusMes message.NotifyUserStatusMes
	notifyUserStatusMes.UserId = userId
	notifyUserStatusMes.Status = message.UserOnline
	// 将 notifyUserStatusMes 序列化
	data, err := json.Marshal(notifyUserStatusMes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}
	// 将序列化后的 notifyUserStatusMes 赋值给 mes.Data
	mes.Data = string(data)
	// 对 mes 再次序列化，准备发送。
	data, err = json.Marshal(mes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}
	// 创建 Transfer实例
	tf := &utils.Transfer{
		Conn: this.Conn,
	}
	// 发送消息
	err = tf.WritePkg(data)
	if err != nil {
		fmt.Println("NotifyMeOnline err=", err)
		return
	}
}

// 注册用户
func (this *UserProcess) ServerProcessRegister(mes *message.Message) (err error) {
	// 1 先从 mes 中取出 mes.Data ，并直接反序列化成 RegisterMes
	var registerMes message.RegisterMes
	err = json.Unmarshal([]byte(mes.Data), &registerMes)
	if err != nil {
		fmt.Println("json.Unmarshal fail err=", err)
		return
	}
	// 1 先声明一个 resMes，用于响应
	var resMes message.Message
	resMes.Type = message.RegisterResMesType
	var registerResMes message.RegisterResMes
	// 需要到 redis 数据库去完成注册。
	// 1 使用 model.MyUserDao 到 redis 去验证。
	err = model.MyUserDao.Register(&registerMes.User)
	if err != nil {
		if err == model.ERROR_USER_EXISTS {
			registerResMes.Code = 505
			registerResMes.Error = model.ERROR_USER_EXISTS.Error()
		} else {
			registerResMes.Code = 506
			registerResMes.Error = "注册发生未知错误"
		}
	} else {
		registerResMes.Code = 200
	}
	data, err := json.Marshal(registerResMes)
	if err != nil {
		fmt.Println("json.Marshal fail", err)
		return
	}
	// 4 将 data 赋值给 resMes
	resMes.Data = string(data)
	// 5 对 resMes 进行序列化，准备发送
	data, err = json.Marshal(resMes)
	if err != nil {
		fmt.Println("json.Marshal fail", err)
		return
	}
	// 6 发送 data 到客户端
	tf := &utils.Transfer{
		Conn: this.Conn,
	}
	err = tf.WritePkg(data)
	return
}

// 处理登录请求
func (this *UserProcess) ServerProcessLogin(mes *message.Message) (err error) {
	// 1 先从 mes 中取出 mes.Data ，并直接反序列化成 LoginMes
	var loginMes message.LoginMes
	err = json.Unmarshal([]byte(mes.Data), &loginMes)
	if err != nil {
		fmt.Println("json.Unmarshal fail err=", err)
		return
	}
	// 2 声明一个 resMes
	var resMes message.Message
	resMes.Type = message.LoginResMesType
	// 3 再声明一个 LoginResMes，并完成赋值
	var loginResMes message.LoginResMes
	// 使用 model.MyUserDao 到 redis 去验证
	user, err := model.MyUserDao.Login(loginMes.UserId, loginMes.UserPwd)
	if err != nil {
		if err == model.ERROR_USER_NOTEXISTS {
			loginResMes.Code = 500
			loginResMes.Error = err.Error()
		} else if err == model.ERROR_USER_PWD {
			loginResMes.Code = 403
			loginResMes.Error = err.Error()
		} else {
			loginResMes.Code = 505
			loginResMes.Error = "服务器内部错误"
		}
	} else {
		loginResMes.Code = 200
		// 因为用户登录成功，就把该登录成功的用户放入到 userMgr 中
		// 将登录成功的用户的 userId 赋给 this
		this.UserId = loginMes.UserId
		userMgr.AddOnlineUser(this)
		// 通知其它的在线用户， 我上线了
		this.NotifyOthersOnlineUser(loginMes.UserId)
		// 将当前在线用户的 id 放入到 loginResMes.UsersId
		// 遍历 userMgr.onlineUsers
		for id, _ := range userMgr.onlineUsers {
			loginResMes.UsersId = append(loginResMes.UsersId, id)
		}
		fmt.Println(user, "登录成功")
	}
	// 4 将 loginResMes 序列化
	data, err := json.Marshal(loginResMes)
	if err != nil {
		fmt.Println("json.Marshal fail", err)
		return
	}
	// 5 将 data 赋值给 resMes
	resMes.Data = string(data)
	// 6 对 resMes 进行序列化，准备发送
	data, err = json.Marshal(resMes)
	if err != nil {
		fmt.Println("json.Marshal fail", err)
		return
	}
	// 7 writePkg函数，用于发送 data
	// 因为使用分层模式(mvc), 先创建一个 Transfer 实例，然后发送
	tf := &utils.Transfer{
		Conn: this.Conn,
	}
	err = tf.WritePkg(data)
	return
}
